package com.zhongtf.utils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


public class RSAUtil {

    public static BASE64Encoder base64Encoder = new BASE64Encoder();
    public static BASE64Decoder base64Decoder = new BASE64Decoder();
    public static final String SIGN_ALGORITHMS = "SHA256WithRSA";
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    /** */
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** */
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;


    // 公钥216
    private static String publicKeyStr;
    private static String privateKeyStr;
    // 生成密钥对
    private static void generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator;
        keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 获取公钥，并以base64格式打印出来
        PublicKey publicKey = keyPair.getPublic();
        publicKeyStr = new String(base64Encoder.encode(publicKey.getEncoded()));
        System.out.println("公钥"+publicKeyStr);
        // 获取私钥，并以base64格式打印出来
        PrivateKey privateKey = keyPair.getPrivate();
        privateKeyStr = new String(base64Encoder.encode(privateKey.getEncoded()));
        System.out.println("私钥"+privateKeyStr);
    }


    /**
     * 签名
     *
     * @param content
     * @param privateKey
     * @return
     */
    public static String sign(String content, String privateKey) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateKey));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);
            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));
            byte[] signed = signature.sign();
            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 验签
     *
     * @param content
     * @param sign
     * @param publicKey
     * @return
     */
    public static boolean verify(String content, String sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64.getMimeDecoder().decode(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));

            return signature.verify(Base64.getMimeDecoder().decode(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    public static PublicKey getPublicKey(String key) throws Exception {
        System.out.println(key);
        byte[] keyBytes = Base64.getMimeDecoder().decode(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes = Base64.getMimeDecoder().decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    /**
     * 公钥分段加密
     *
     * @param content
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String publicEncrpyt(String content, String publicKeyStr) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(1, getPublicKey(publicKeyStr));
        byte[] bytes = content.getBytes(DEFAULT_CHARSET);

        int inputLen = bytes.length;
        int offSet = 0;
        byte[] cache;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.getEncoder().encodeToString(encryptedData);
    }


    /**
     * 私钥分段加密
     *
     * @param content
     * @param privateKeyStr
     * @return
     * @throws Exception
     */
    public static String privateEncrpyt(String content, String privateKeyStr) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(1, getPrivateKey(privateKeyStr));
        byte[] bytes = content.getBytes(DEFAULT_CHARSET);

        int inputLen = bytes.length;
        int offSet = 0;
        byte[] cache;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.getEncoder().encodeToString(encryptedData);
    }


    /**
     * 私钥分段解密
     *
     * @param content
     * @param privateKeyStr
     * @return
     * @throws Exception
     */
    public static String privateDecrypt(String content, String privateKeyStr) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(2, getPrivateKey(privateKeyStr));
        byte[] bytes = Base64.getMimeDecoder().decode(content);
        int inputLen = bytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return new String(decryptedData);
    }


    /**
     * 公钥分段解密
     *
     * @param content
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String publicDecrypt(String content, String publicKeyStr) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(2, getPublicKey(publicKeyStr));
        byte[] bytes = Base64.getMimeDecoder().decode(content);
        int inputLen = bytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return new String(decryptedData);
    }


    public static void main(String[] args) throws Exception {
        String content0 = "asdhaoddddddaosdjosadosaudosaudaosdusadadsadsadsadasdasdasdasdsadsadsadasdasdasdsadasdsadasdsadsadadsadsadadiugtiutujjjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka";
        String content ="m/44'/60'/0'/0/054eee548e3e1430b41e95224f8aa23dd8649b55620a64095c902ff65fa20f460a5cfKQ87WwHgZROROuOAoWw3tiAo2rXZKTobfeacuUth6D7oZNit+FNmM0joBszrz7rBomTZ9MVkQX7vuW9ZoIPzwPARWNu8kFD0oJxEgw+6ZR7qFyh681UIAeUD4IMv61DTf+wv9uqE3Dn0EmbqFvKP7sRR90vS2ZVsES4zvCQ=" ;

        //企业公钥
        String publicKeyStr= "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIIdFxETeR/L06Yk5sf1F/Q1hC/UDgjOeFWqN9\n" +
                "YAytWjE9OaK+R0AtY0GYDSib6VBKl/5TF4n5aFS4dQMLVoBqlkiGi3MTt2iyXCvvW/kF/rxMD+QI\n" +
                "U2L8QYW7WNJIYHK37esKvF83K0GlJBWGycoB2u3qB3ETTAs7tAv3oyGt8wIDAQAB";
        //企业私钥
        String privateKeyStr="MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIgh0XERN5H8vTpiTmx/UX9DWEL9\n" +
                "QOCM54Vao31gDK1aMT05or5HQC1jQZgNKJvpUEqX/lMXifloVLh1AwtWgGqWSIaLcxO3aLJcK+9b\n" +
                "+QX+vEwP5AhTYvxBhbtY0khgcrft6wq8XzcrQaUkFYbJygHa7eoHcRNMCzu0C/ejIa3zAgMBAAEC\n" +
                "gYBvA0UM84Fhp72YkvppOBp5sa2UU3pIpB9ZfGS+pUkxRM/Koem5SdloKf0fxftLyaQUcIaRtCxs\n" +
                "G0ybb7Cf2la1Yn3ozygW/yewKYw20jZ1AQPLkM9xmYm0ftuqPhP6z0K/N4RdVxCVvT7/bwBDwN0B\n" +
                "RcTIpUvy/RmbVTKhRGD4wQJBANGPsKHK1gSH+laOb6Oy3e0rxTRsV/3rjbISvWld+ZkW6xiSqQW4\n" +
                "uxFJFyyV7OGbT+XKSxYE6d7kCM3b3CtDZ7kCQQCmTIauFWzHcWuV93lATj7yzvyEdzLAv4DCh5V8\n" +
                "CqJ+VNotXpD8Ch069hlKXjETbGZqJBGz9B8c9vOF1z/buIELAkEAzXVxmc8CccLXoBFaR0bQ6v0l\n" +
                "BbbLtnpBnDtfVXT7iCq+KINyD9gEIHhmriH382GQvhzN7TK4EP3F2/8ZJ5mYkQJAKjs23JCeTkvU\n" +
                "WYI+LYFxZPIBmJY4slAvn7cU1CpTN6fOvETOpuLep3GF3Kfs6JTXsU61nDB7kjx4fV27Xs4NHwJB\n" +
                "AIHReSGm7wnJvPo3Cyil5Dkaa4xaZC1t7AnwNDc/SrQTColB/lxJfsIkr2c10STS8fogph55GrF6\n" +
                "zEI6o+1E8W8=";
        //generateKeyPair();

        //公钥加密-->私钥签名-->公钥验签-->私钥解密
        String s = publicEncrpyt(content, publicKeyStr);
        System.out.println("公钥加密后"+s);

        //签名     Authorization
        String sign = sign(s, privateKeyStr);
        System.out.println("私钥签名后："+sign);

        //验签
        boolean verify = verify(s, sign, publicKeyStr);
        System.out.println("用公钥验签后"+verify);

        String s1 = privateDecrypt(s, privateKeyStr);
        System.out.println("解密后"+s1 );

    }


}
